#pragma once



#include <uxtheme.h> //SetWindowTheme
#include <vssym32.h> //theme  constants
#pragma comment(lib, "uxtheme.lib")



namespace micro
{
namespace gui
{


class QTheme
{
public:
// Data members
    HTHEME m_hTheme;
    static int m_nIsThemingSupported;

// Constructor
    QTheme( HTHEME hTheme = nullptr ) : m_hTheme( hTheme )
    {
        IsThemingSupported();
    }
    ~QTheme()
    {
        CloseThemeData();
    }

// Operators and helpers
    bool IsThemeNull() const
    {
        return ( m_hTheme == nullptr );
    }

    QTheme & operator =( HTHEME hTheme )
    {
        m_hTheme = hTheme;
        return *this;
    }

    operator bool()const
    {
        return ( m_hTheme != nullptr );
    }
    operator HTHEME() const
    {
        return m_hTheme;
    }

    void Attach( HTHEME hTheme )
    {
        m_hTheme = hTheme;
    }

    HTHEME Detach()
    {
        HTHEME hTheme = m_hTheme;
        m_hTheme = nullptr;
        return hTheme;
    }

// Theme support helper
    static bool IsThemingSupported()
    {

        if ( m_nIsThemingSupported == -1 )
        {
            HMODULE hThemeDLL = ::LoadLibrary( _T( "uxtheme.dll" ) );
            m_nIsThemingSupported = ( hThemeDLL != nullptr ) ? 1 : 0;

            if ( hThemeDLL != nullptr )
                ::FreeLibrary( hThemeDLL );
        }



        ASSERT( m_nIsThemingSupported != -1 );
        return ( m_nIsThemingSupported == 1 );
    }

// Operations and theme properties
    HTHEME OpenThemeData( HWND hWnd, LPCWSTR pszClassList )
    {
        if ( !IsThemingSupported() )
            return nullptr;

        ASSERT( m_hTheme == nullptr );
        m_hTheme = ::OpenThemeData( hWnd, pszClassList );
        return m_hTheme;
    }

    HRESULT CloseThemeData()
    {
        HRESULT hRet = S_FALSE;

        if ( m_hTheme != nullptr )
        {
            hRet = ::CloseThemeData( m_hTheme );

            if ( SUCCEEDED( hRet ) )
                m_hTheme = nullptr;
        }

        return hRet;
    }

    HRESULT DrawThemeBackground( HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = nullptr )
    {
        ASSERT( m_hTheme != nullptr );
        return ::DrawThemeBackground( m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect );
    }

    HRESULT DrawThemeBackgroundEx( HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS * pOptions = nullptr )
    {
        ASSERT( m_hTheme != nullptr );
        return ::DrawThemeBackgroundEx( m_hTheme, hDC, nPartID, nStateID, pRect, pOptions );
    }

    HRESULT DrawThemeText( HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect )
    {
        ASSERT( m_hTheme != nullptr );
        return ::DrawThemeText( m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect );
    }

    HRESULT GetThemeBackgroundContentRect( HDC hDC, int nPartID, int nStateID,  LPCRECT pBoundingRect, LPRECT pContentRect ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeBackgroundContentRect( m_hTheme, hDC, nPartID, nStateID,  pBoundingRect, pContentRect );
    }

    HRESULT GetThemeBackgroundExtent( HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeBackgroundExtent( m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect );
    }

    HRESULT GetThemePartSize( HDC hDC, int nPartID, int nStateID, LPRECT pRect, enum THEMESIZE eSize, LPSIZE pSize ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemePartSize( m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize );
    }

    HRESULT GetThemeTextExtent( HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT  pBoundingRect, LPRECT pExtentRect ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeTextExtent( m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect );
    }

    HRESULT GetThemeTextMetrics( HDC hDC, int nPartID, int nStateID, PTEXTMETRIC  pTextMetric ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeTextMetrics( m_hTheme, hDC, nPartID, nStateID, ( PTEXTMETRIC )pTextMetric );
    }

    HRESULT GetThemeBackgroundRegion( HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN * pRegion ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeBackgroundRegion( m_hTheme, hDC, nPartID, nStateID, pRect, pRegion );
    }

    HRESULT HitTestThemeBackground( HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD * pwHitTestCode ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::HitTestThemeBackground( m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode );
    }

    HRESULT DrawThemeEdge( HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = nullptr )
    {
        ASSERT( m_hTheme != nullptr );
        return ::DrawThemeEdge( m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect );
    }

    HRESULT DrawThemeIcon( HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex )
    {
        ASSERT( m_hTheme != nullptr );
        return ::DrawThemeIcon( m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex );
    }

    BOOL IsThemePartDefined( int nPartID, int nStateID ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::IsThemePartDefined( m_hTheme, nPartID, nStateID );
    }

    BOOL IsThemeBackgroundPartiallyTransparent( int nPartID, int nStateID ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::IsThemeBackgroundPartiallyTransparent( m_hTheme, nPartID, nStateID );
    }

    HRESULT GetThemeColor( int nPartID, int nStateID, int nPropID, COLORREF * pColor ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeColor( m_hTheme, nPartID, nStateID, nPropID, pColor );
    }

    HRESULT GetThemeMetric( HDC hDC, int nPartID, int nStateID, int nPropID, int * pnVal ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeMetric( m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal );
    }

    HRESULT GetThemeString( int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeString( m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars );
    }

    HRESULT GetThemeBool( int nPartID, int nStateID, int nPropID, BOOL * pfVal ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeBool( m_hTheme, nPartID, nStateID, nPropID, pfVal );
    }

    HRESULT GetThemeInt( int nPartID, int nStateID, int nPropID, int * pnVal ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeInt( m_hTheme, nPartID, nStateID, nPropID, pnVal );
    }

    HRESULT GetThemeEnumValue( int nPartID, int nStateID, int nPropID, int * pnVal ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeEnumValue( m_hTheme, nPartID, nStateID, nPropID, pnVal );
    }

    HRESULT GetThemePosition( int nPartID, int nStateID, int nPropID, LPPOINT pPoint ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemePosition( m_hTheme, nPartID, nStateID, nPropID, pPoint );
    }

    // deprecated
    HRESULT GetThemeFont( int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONT * pFont ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeFont( m_hTheme, hDC, nPartID, nStateID, nPropID, pFont );
    }

    HRESULT GetThemeFont( HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONT * pFont ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeFont( m_hTheme, hDC, nPartID, nStateID, nPropID, pFont );
    }

    HRESULT GetThemeRect( int nPartID, int nStateID, int nPropID, LPRECT pRect ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeRect( m_hTheme, nPartID, nStateID, nPropID, pRect );
    }

    HRESULT GetThemeMargins( HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeMargins( m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins );
    }

    HRESULT GetThemeIntList( int nPartID, int nStateID, int nPropID, INTLIST * pIntList ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeIntList( m_hTheme, nPartID, nStateID, nPropID, pIntList );
    }

    HRESULT GetThemePropertyOrigin( int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN * pOrigin ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemePropertyOrigin( m_hTheme, nPartID, nStateID, nPropID, pOrigin );
    }

    HRESULT GetThemeFilename( int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeFilename( m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars );
    }

    COLORREF GetThemeSysColor( int nColorID ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeSysColor( m_hTheme, nColorID );
    }

    HBRUSH GetThemeSysColorBrush( int nColorID ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeSysColorBrush( m_hTheme, nColorID );
    }

    int GetThemeSysSize( int nSizeID ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeSysSize( m_hTheme, nSizeID );
    }

    BOOL GetThemeSysBool( int nBoolID ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeSysBool( m_hTheme, nBoolID );
    }

    HRESULT GetThemeSysFont( int nFontID, LOGFONT * plf ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeSysFont( m_hTheme, nFontID, ( LOGFONT * )plf );
    }

    HRESULT GetThemeSysString( int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeSysString( m_hTheme, nStringID, pszStringBuff, cchMaxStringChars );
    }

    HRESULT GetThemeSysInt( int nIntID, int * pnValue ) const
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeSysInt( m_hTheme, nIntID, pnValue );
    }


    HTHEME OpenThemeDataEx( HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags )
    {
        if ( !IsThemingSupported() )
            return nullptr;

        ASSERT( m_hTheme == nullptr );
        m_hTheme = ::OpenThemeDataEx( hWnd, pszClassList, dwFlags );
        return m_hTheme;
    }


#if( WINVER>=_WIN32_WINNT_WIN7)
    HRESULT DrawThemeTextEx( HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS * pOptions )
    {
        ASSERT( m_hTheme != nullptr );
        return ::DrawThemeTextEx( m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions );
    }

    HRESULT GetThemeTransitionDuration( int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD & dwDuration )
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeTransitionDuration( m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration );
    }
#endif


    HRESULT DrawThemeParentBackground( HWND hwnd, HDC hDC, const RECT * pRect = nullptr )
    {
        ASSERT( m_hTheme != nullptr );

        return ::DrawThemeParentBackground( hwnd, hDC, pRect );

    }


#if (_WIN32_WINNT >= 0x0600)
    HRESULT GetThemeBitmap( int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP & hBitmap )
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeBitmap( m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap );
    }

    HRESULT GetThemeStream( int nPartID, int nStateID, int nPropID, VOID ** ppvStream, DWORD * pcbStream, HINSTANCE hInstance )
    {
        ASSERT( m_hTheme != nullptr );
        return ::GetThemeStream( m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance );
    }
#endif // (_WIN32_WINNT >= 0x0600)
};

__declspec( selectany ) int QTheme::m_nIsThemingSupported = -1;




}//namespace



}//micro